// 简单的 domain, 都是 与 关系的, 可以用 dict 传参数,
// 复杂的 domain, 有 或 非 关系的, 依然可以用 list 格式
// global_domain 是个函数, 用于设置全局的/与用户有关的过滤条件
function _format_domain(self, domain_src = {}) {
  // console.log('_format_domain ,', self.model, self, domain_src)

  const global = self.global_domain()

  // eslint-disable-next-line object-curly-spacing
  // const { domain_default = {} } = self.configs || {}
  // TBD 不再使用 configs 了, 应该将 本文中 所有的 self.configs 改为 metadata

  // eslint-disable-next-line object-curly-spacing
  const { domain: domain_default = {} } = self.metadata || {}

  let domain = []
  let domain_dict = {}
  if (Array.isArray(domain_default)) {
    domain = [...domain, ...domain_default]
  } else {
    domain_dict = { ...domain_dict, ...domain_default }
  }

  if (Array.isArray(domain_src)) {
    domain = [...domain, ...domain_src]
  } else {
    domain_dict = { ...domain_dict, ...domain_src }
  }

  if (Array.isArray(global)) {
    domain = [...domain, ...global]
  } else {
    domain_dict = { ...domain_dict, ...global }
  }

  return [domain, domain_dict]
}

export class ModelClass {
  constructor(options = {}) {
    const { model, metadata, rpc, env } = options
    this.model = model
    this.metadata = metadata
    this.rpc = rpc
    this.env = env
  }

  get_userinfo() {
    return this.rpc.get_userinfo()
  }

  call(method, args, kwargs) {
    return this.rpc.call(this.model, method, args, kwargs)
  }

  // TBD  判断 数组或 字典
  global_domain(domain = {}) {
    // to be overrided
    // const domain = { ...domain_src }
    // const userinfo = this.get_userinfo()
    // const { uid } = userinfo
    // domain.create_uid = uid
    return domain
  }

  async get_options(fields) {
    const res = await this.call('get_options', [fields])
    return res
  }

  async default_get(fields, context) {
    const method = 'default_get'
    const args = [fields]
    const kwargs = { context }
    const res = await this.call(method, args, kwargs)
    return res
  }

  // 2019-12-8 no used
  async fields_get(kwargs) {
    // const { allfields, attributes } = kwargs
    const method = 'fields_get'
    const args = []
    const res = await this.call(method, args, kwargs)
    return res
  }

  // Not Used
  ref(xmlid) {
    // get model and id from xmlid
    return this.env('ir.model.data').call('xmlid_to_res_model_res_id', [
      xmlid,
      true
    ])
  }

  search_read(kwargs) {
    return this.call('search_read', [], kwargs)
  }

  async search_count(query = {}) {
    const {
      domain = {}, // 目前的前端 都是简单的 domian ={}
      domain2 = []
    } = query
    const method = 'search_count2'
    const [domain_list, domain_dict] = _format_domain(this, domain)
    const args = []
    const kwargs = {
      domain: [...domain2, ...domain_list],
      domain2: domain_dict
    }
    return await this.call(method, args, kwargs)
  }

  async browse_one(id, query = {}) {
    const res = await this.browse(id, query)
    return res && res.length === 1 ? res[0] : {}
  }

  async browse(rid, query = {}) {
    // eslint-disable-next-line object-curly-spacing
    const { fields } = query
    const method = 'read2'

    // 判断 id 是数组或 int
    const args = [
      Array.isArray(rid) ? rid.map(item => parseInt(item)) : parseInt(rid)
    ]
    const kwargs = {
      fields: fields // || { display_name: null }
    }

    // read2 返回值是 数组
    const records = await this.call(method, args, kwargs)
    return records
  }

  async search(query = {}) {
    // const sss = await this.fields_get()
    const {
      domain = {}, // 目前的前端 都是简单的 domian ={}
      domain2 = [],
      fields = {},
      page = 1,
      limit = 0,
      offset,
      order
    } = query

    // console.log('xxxxxxx,search', domain2)

    const [domain_list, domain_dict] = _format_domain(this, domain)

    const method = 'search_read2'
    const args = []
    const kwargs = {
      domain: [...domain2, ...domain_list],
      domain2: domain_dict,
      fields: fields || { name: null },
      offset: offset !== undefined ? offset : (page - 1) * limit,
      limit,
      order
    }

    const records = await this.call(method, args, kwargs)

    return records
  }

  async search_one(kwargs = {}) {
    const res = await this.search(kwargs)
    if (res.length) {
      return res[0]
    } else {
      return {}
    }
  }

  async update_or_create(values, kwargs = {}) {
    console.log('update_or_create, ', values, kwargs)
    const { domain } = kwargs

    if (domain) {
      const rec = await this.search_one({ domain })
      if (rec.id) {
        return this.write({
          values: {
            id: rec.id,
            ...values
          }
        })
      } else {
        return this.create(values, kwargs)
      }
    } else {
      return this.write(values, kwargs)
    }
  }

  async create(values = {}, kwargs = {}) {
    const method = 'create2'
    const args = [values]
    return await this.call(method, args, kwargs)
  }

  async write(values, kwargs = {}) {
    // console.log('xxxxx, write', values)
    const method = 'write2'
    const rid = values.id
    const values2 = { ...values }
    delete values2.id
    const args = [rid, values2]
    return await this.call(method, args, kwargs)
  }

  async unlink(rid) {
    const method = 'unlink'
    const args = [rid]

    return await this.call(method, args)
  }

  async wizard_submit(rid, payload) {
    const { model, values, method: wizard_method } = payload
    const { id: wizard_id } = values
    const vals = { ...values }
    delete vals.id
    const method = 'wizard_submit'
    const args = [rid, model, wizard_id, vals, wizard_method]
    const kwargs = {}
    return await this.call(method, args, kwargs)
  }

  async wizard_create(rid, payload) {
    console.log('on odoojs model, wizard_create', rid, payload)
    // eslint-disable-next-line object-curly-spacing
    const { model, values = {}, context = {}, fields = {} } = payload
    const method = 'wizard_create'
    const args = [rid, model, values]
    const kwargs = { context, fields }
    return await this.call(method, args, kwargs)
  }

  async report_print(params) {
    // eslint-disable-next-line object-curly-spacing
    const { model, values = {}, fields = {} } = params

    const vals = { ...values }
    delete vals.id

    // console.log('report_print', params)

    const res = await this.call('report_print', [model, values.id, vals], {
      fields
    })
    // console.log('xxxx,rpt2,', res)

    return res
  }

  // async report_wizard_create(params) {
  //   // eslint-disable-next-line object-curly-spacing
  //   const { model, fields = {}, context = {} } = params
  //   const wizard = await this.call('wizard_create', [0, model, {}], {
  //     // onchange: ['_onchange_company_id'],
  //     fields,
  //     context
  //   })
  //   console.log('xxxx,wizard,', wizard)

  //   return wizard
  // }
}

const creater = options => {
  return new ModelClass(options)
}
export default creater
